C++

MFC 윈도우 프로그래밍 – 널널한 개발자 TV

 

https://www.youtube.com/watch?v=ZUGbkZVXMA4&list=PLXvgR_grOs1CyJDnWeUTqbmKG1VFQM72e&index=1

 

  1. MFC SDI 구조 주소록 예제 작성방법
  2. 키보드 이벤트 처리 핵심원리
  3. 키보드 해킹 원리 (※취급주의)

 


 

MFC Win32 API
메시지 드리븐 방식

설치 시 :
최신 v143 빌드 도구용 C++ MFC(x86 및 x64)
v143 빌드 도구에 대한 C++/CLI 지원(최신)
v143 빌드 도구용 C++ 모듈(x64/x86)
Windows 11 SDK (10.0.22000.0)
Windows 10 SDK (10.0.20348.0)

개발 설정 : Visual C++
Dark Theme (2019) – Mads Kristensen

도구 – 옵션 – 환경 – 글꼴 및 색 – Consolas 11

디버그 – 창 – 메모리 윈도우 (오른쪽에 도킹 4 바이트 씩 표)

wWinMain – 시작점

윈도우 – 속성 : (클래스) 종류

새 프로젝트
타입 : Single Document
스타일 : MFC standard

# APP
InitInstance() 메인 함수 시작
ExitInstance() 인스턴스 종료할 때

CWinAPP : 제어
CFrameWnd : GUI
CView : GUI
CDocument : 자료구조

 


 

 1. MFC SDI 구조 주소록 예제 작성방법

 

# 클래스 뷰 – View 클래스에서 – 추가 – 변수 추가
m_wndList, CListBox, private

# 리스트박스 만들기
클래스 뷰 – View 클래스 – 속성 – 메시지 탭 – WM_CREATE
m_wndList.Create(WS_CHILD | WS_VISIBLE | LBS_STANDARD | WS_HSCROLL, CRect(0, 0, 300, 400), this, 1234); // ID는 임시로 1234로

# 리소스 뷰 – 메뉴
주소관리
1. 주소추가(ID_New_Addr)
2. 검색(ID_SEARCH)
// 이벤트 처리기 추가 (View에 만들어라.)

# 리소스 뷰 – 다이얼로그 – 다이얼로그 추가
IDD_DIALOG_NEW_ADDR
클래스 추가 – CDlgNewAddr

# 방금 만든 다이얼르그 박스에 에디트 컨트롤 2개 추가
IDC_EDIT_NAME, IDC_EDIT_PHONE
변수 추가 (값) : m_strName, m_strPhone

# 만든 대화상자를 사용하기 위해서 View 파일 상단에 추가
#include “CDlgNewAddr.h” 추가

Ctrl + T : 다이얼로그 테스트
Ctrl + D : 탭 오더

# 클래스 뷰 – 클래스 추가
클래스 이름 : CUserData
베이스 클래스 : CObject (메모리 릭 방지를 더 편하게 하기 위해)

# pch.h 파일은 모든 파일이 포함하기 때문에 여기에 #include 하면 전역적으로 사용하기 편함
#include “CUserData.h”

# 클래스 뷰 – Doc 파일 – 함수 추가 (데이터 저장 함수)
함수 이름 : NewAddr
액세스 : public
매개 변수 : CString name, CString phone

# Doc 파일에 추가
CPtrList m_ptrList (포인터를 링크드리스트 1차원리스트로 관리)

# 클래스 뷰 – Doc 파일 – 함수 추가 (메모리 해제 함수)
함수 이름 : ReleaseList()
반환 형식 : void

# View 파일에서 소멸자에서 메모리 해제작업을 해준다. ReleaseList()

# 클래스 뷰 – Doc 파일 – 함수 추가
함수 이름 : FindUser
반환 형식 : UserData
매개 변수 : CString name

# attempting to reference a deleted function 에러 메시지 뜨면 복사 생성자를 안만들어서 그런것임.

 

# Doc 헤더 파일
protected:
    CPtrList m_ptrList;


# Doc 소스 파일
int CAddrBookDoc::NewAddr(CString name, CString phone)
{
    CUserData* pNew = new CUserData(name, phone);
    m_ptrList.AddTail(pNew);
    return 0;
}


void CAddrBookDoc::ReleaseList()
{
    POSITION pos = m_ptrList.GetHeadPosition();
    while (pos != NULL) {
        CUserData* pNode = (CUserData*)m_ptrList.GetNext(pos);
        OutputDebugString(pNode->GetName());
        delete pNode;
    }
}


CUserData CAddrBookDoc::FindUser(CString name)
{
    POSITION pos = m_ptrList.GetHeadPosition();
    while (pos != NULL) {
        CUserData* pNode = (CUserData*)m_ptrList.GetNext(pos);
        if (pNode->GetName() == name)
            return *pNode;
    }
    
    return CUserData(_T(""), _T(""));
}

 

# View 헤더 파일
private:
    CListBox m_wndList;

# View 소스 파일
#include "CDlgNewAddr.h"

CAddrBookView::~CAddrBookView()
{
    GetDocument()->ReleaseList();
}

int CAddrBookView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;

    m_wndList.Create(WS_CHILD | WS_VISIBLE | LBS_STANDARD | WS_HSCROLL,
        CRect(0, 0, 300, 400), this, 1234); // 임시로 1234로

    //for (int i = 0; i < 10; i++)	
    //	m_wndList.AddString(_T("TEST STRING"));
    

    return 0;
}


void CAddrBookView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);

    m_wndList.MoveWindow(0, 0, 300, cy);
}


void CAddrBookView::OnNewAddr()
{
    CDlgNewAddr dlg;
    if (dlg.DoModal() == IDOK)
    {
        m_wndList.AddString(dlg.m_strName + _T("[") + dlg.m_strPhone + _T("]"));
        GetDocument()->NewAddr(dlg.m_strName, dlg.m_strPhone);
    }	
}


void CAddrBookView::OnSearch()
{
    CDlgNewAddr dlg;
    if (dlg.DoModal() == IDOK)
    {		
        CUserData user = GetDocument()->FindUser(dlg.m_strName);
        if (user.GetName().IsEmpty())
            AfxMessageBox(_T("Not Found"));
        else
            AfxMessageBox(user.GetName() + _T(" ") + user.GetPhone());
    }
}

 

 

# CUserData 헤더 파일
#pragma once
#include <afx.h>
class CUserData :
    public CObject
{
public:
    CUserData(CString name, CString phone) {
        m_strName = name;
        m_strPhone = phone;
    }

    CUserData(const CUserData& rhs) {
        // 복사 생성자
        this->m_strName = rhs.m_strName;
        this->m_strPhone = rhs.m_strPhone;
    }

    CString GetName() { return m_strName; }
    CString GetPhone() { return m_strPhone; }

private:
    CString m_strName;
    CString m_strPhone;
};

 

 

#pch.h 파일 (클래스의 전역적 사용을 위해)

#include "framework.h"
#include "CUserData.h"

 

 

 


 

2. 키보드 이벤트 처리 핵심원리

 

# 클래스 뷰 – View 클래스 – 속성 – 메시지 탭 – WM_KEYDOWN

 

void CHelloMFCView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    CClientDC dc(this);

    static CString strData;

    CString strTmp;
    strTmp.Format(_T("%c"), nChar);
    strData += strTmp;

    dc.TextOut(10, 10, strData);

    CView::OnKeyDown(nChar, nRepCnt, nFlags);
}

 

 

 


 

2. 키보드 해킹 원리

 

HHOOK g_hook;
LRESULT CALLBACK KeyHookCallback(int code, WPARAM wParam, LPARAM lParam)
{
    LPKBDLLHOOKSTRUCT khs = (LPKBDLLHOOKSTRUCT)lParam;
    if (wParam == WM_KEYDOWN)
    {	
        OutputDebugStringA((char*)&khs->vkCode);
    }
    return CallNextHookEx(g_hook, code, wParam, lParam);
}

void CMFCHookDlg::SetHook()
{
    if (g_hook != NULL)
        UnHook();
    g_hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyHookCallback, NULL, NULL);
}

void CMFCHookDlg::UnHook()
{
    if (g_hook != NULL)
    {
        UnhookWindowsHookEx(g_hook);
    }
}

 

 

 

Related posts

Leave a Comment